/*
 * Copyright (c) 2010-2020 Belledonne Communications SARL.
 *
 * This file is part of linphone-android
 * (see https://www.linphone.org).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.newlink.building.compatibility

import android.app.Activity
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.Vibrator
import android.provider.Settings
import android.telephony.TelephonyManager
import android.view.View
import android.view.WindowManager
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.Fragment
import com.newlink.building.common_base.utils.NLog
import com.newlink.building.notifications.Notifiable
import com.newlink.building.notifications.NotificationsManager
import com.newlink.building.telecom.Module_Phone_NativeCallWrapper
import org.linphone.core.Call
import org.linphone.core.ChatRoom
import org.linphone.mediastream.Version
import java.util.*

@Suppress("DEPRECATION")
class Module_Phone_Compatibility {
    companion object {
        const val BLUETOOTH_CONNECT = "android.permission.BLUETOOTH_CONNECT"

        const val FOREGROUND_SERVICE_TYPE_DATA_SYNC =
            1 // ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
        const val FOREGROUND_SERVICE_TYPE_PHONE_CALL =
            4 // ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
        const val FOREGROUND_SERVICE_TYPE_CAMERA = 64 // ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
        const val FOREGROUND_SERVICE_TYPE_MICROPHONE =
            128 // ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
        const val FOREGROUND_SERVICE_TYPE_SPECIAL_USE =
            1073741824 // ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE

        fun hasPermission(context: Context, permission: String): Boolean {
            return when (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) {
                true -> Module_Phone_Api23Compatibility.hasPermission(context, permission)
                else -> context.packageManager.checkPermission(
                    permission,
                    context.packageName
                ) == PackageManager.PERMISSION_GRANTED
            }
        }

        // See https://developer.android.com/about/versions/11/privacy/permissions#phone-numbers
        fun hasReadPhoneStateOrNumbersPermission(context: Context): Boolean {
            return if (Version.sdkAboveOrEqual(Version.API30_ANDROID_11)) {
                Module_Phone_Api30Compatibility.hasReadPhoneNumbersPermission(context)
            } else {
                Module_Phone_Api29Compatibility.hasReadPhoneStatePermission(context)
            }
        }

        // See https://developer.android.com/about/versions/11/privacy/permissions#phone-numbers
        fun requestReadPhoneStateOrNumbersPermission(fragment: Fragment, code: Int) {
            Module_Phone_Api23Compatibility.requestReadPhoneStatePermission(fragment, code)
        }

        fun hasBluetoothConnectPermission(context: Context): Boolean {
            if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
                return Module_Phone_Api31Compatibility.hasBluetoothConnectPermission(context)
            }
            return true
        }

        // See https://developer.android.com/about/versions/11/privacy/permissions#phone-numbers
        fun hasTelecomManagerPermissions(context: Context): Boolean {
            return if (Version.sdkAboveOrEqual(Version.API30_ANDROID_11)) {
                Module_Phone_Api30Compatibility.hasTelecomManagerPermission(context)
            } else {
                Api26Compatibility.hasTelecomManagerPermission(context)
            }
        }

        fun requestTelecomManagerPermissions(activity: Activity, code: Int) {
            if (Version.sdkAboveOrEqual(Version.API30_ANDROID_11)) {
                Module_Phone_Api30Compatibility.requestTelecomManagerPermission(activity, code)
            } else {
                Api26Compatibility.requestTelecomManagerPermission(activity, code)
            }
        }

        fun getDeviceName(context: Context): String {
            return when (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) {
                true -> Module_Phone_Api25Compatibility.getDeviceName(context)
                else -> Module_Phone_Api21Compatibility.getDeviceName(context)
            }
        }

        fun createPhoneListener(telephonyManager: TelephonyManager): Module_Phone_PhoneStateInterface {
            return if (Version.sdkStrictlyBelow(Version.API31_ANDROID_12)) {
                Module_Phone_PhoneStateListener(telephonyManager)
            } else {
                Module_Phone_TelephonyListener(telephonyManager)
            }
        }

        /* UI */

        fun setShowWhenLocked(activity: Activity, enable: Boolean) {
            if (Version.sdkStrictlyBelow(Version.API27_OREO_81)) {
                Module_Phone_Api21Compatibility.setShowWhenLocked(activity, enable)
            } else {
                Module_Phone_Api27Compatibility.setShowWhenLocked(activity, enable)
            }
        }

        fun setTurnScreenOn(activity: Activity, enable: Boolean) {
            if (Version.sdkStrictlyBelow(Version.API27_OREO_81)) {
                Module_Phone_Api21Compatibility.setTurnScreenOn(activity, enable)
            } else {
                Module_Phone_Api27Compatibility.setTurnScreenOn(activity, enable)
            }
        }

        fun requestDismissKeyguard(activity: Activity) {
            if (Version.sdkStrictlyBelow(Version.API27_OREO_81)) {
                Module_Phone_Api21Compatibility.requestDismissKeyguard(activity)
            } else {
                Module_Phone_Api27Compatibility.requestDismissKeyguard(activity)
            }
        }

        fun getBitmapFromUri(context: Context, uri: Uri): Bitmap {
            return if (Version.sdkStrictlyBelow(Version.API29_ANDROID_10)) {
                Module_Phone_Api21Compatibility.getBitmapFromUri(context, uri)
            } else {
                Module_Phone_Api29Compatibility.getBitmapFromUri(context, uri)
            }
        }

        /* Notifications */

        fun createNotificationChannels(
            context: Context,
            notificationManager: NotificationManagerCompat
        ) {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                Api26Compatibility.createServiceChannel(context, notificationManager)
                Api26Compatibility.createMissedCallChannel(context, notificationManager)
                Api26Compatibility.createIncomingCallChannel(context, notificationManager)
                if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
                    Module_Phone_Api29Compatibility.createMessageChannel(context, notificationManager)
                } else {
                    Api26Compatibility.createMessageChannel(context, notificationManager)
                }
            }
        }

        fun getChannelImportance(
            notificationManager: NotificationManagerCompat,
            channelId: String
        ): Int {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                return Api26Compatibility.getChannelImportance(notificationManager, channelId)
            }
            return NotificationManagerCompat.IMPORTANCE_DEFAULT
        }

        fun getOverlayType(): Int {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                return Api26Compatibility.getOverlayType()
            }
            return WindowManager.LayoutParams.TYPE_PHONE
        }

        fun createIncomingCallNotification(
            context: Context,
            call: Call,
            notifiable: Notifiable,
            pendingIntent: PendingIntent,
            notificationsManager: NotificationsManager
        ): Notification {
            val manufacturer = Build.MANUFACTURER.lowercase(Locale.getDefault())
            // Samsung One UI 4.0 (API 31) doesn't (currently) display CallStyle notifications well
            // Tested on Samsung S10 and Z Fold 2
//            if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12) && manufacturer != "samsung") {
//                return Api31Compatibility.createIncomingCallNotification(context, call, notifiable, pendingIntent, notificationsManager)
//            } else
            if (manufacturer == "xiaomi") { // Xiaomi devices don't handle CustomHeadsUpContentView correctly
                return Module_Phone_XiaomiCompatibility.createIncomingCallNotification(
                    context,
                    call,
                    notifiable,
                    pendingIntent,
                    notificationsManager
                )
            }
            if (manufacturer == "samsung") {
                return Api26Compatibility.createIncomingCallNotificationWithoutNumber(
                    context,
                    call,
                    notifiable,
                    pendingIntent,
                    notificationsManager
                )
            }
            return Api26Compatibility.createIncomingCallNotification(
                context,
                call,
                notifiable,
                pendingIntent,
                notificationsManager
            )
        }

        fun createCallNotification(
            context: Context,
            call: Call,
            notifiable: Notifiable,
            pendingIntent: PendingIntent,
            channel: String,
            notificationsManager: NotificationsManager
        ): Notification {
            val manufacturer = Build.MANUFACTURER.lowercase(Locale.getDefault())

            // Samsung One UI 4.0 (API 31) doesn't (currently) display CallStyle notifications well
            // Tested on Samsung S10 and Z Fold 2

            if (manufacturer == "xiaomi") { // Xiaomi devices don't handle CustomHeadsUpContentView correctly
                return Module_Phone_XiaomiCompatibility.createCallNotification(
                    context,
                    call,
                    notifiable,
                    pendingIntent,
                    channel,
                    notificationsManager
                )
            }
            if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12) && manufacturer != "samsung") {
                return Module_Phone_Api31Compatibility.createCallNotification(
                    context,
                    call,
                    notifiable,
                    pendingIntent,
                    channel,
                    notificationsManager
                )
            }

            return Api26Compatibility.createCallNotification(
                context,
                call,
                notifiable,
                pendingIntent,
                channel,
                notificationsManager
            )
        }

        fun startForegroundService(context: Context, intent: Intent) {

            if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
                Module_Phone_Api31Compatibility.startForegroundService(context, intent)
            } else if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                Api26Compatibility.startForegroundService(context, intent)
            } else {
                Module_Phone_Api21Compatibility.startForegroundService(context, intent)
            }


        }


        fun startForegroundService(
            service: Service,
            notifId: Int,
            notif: Notification?,
            mask: Int = 0
        ) {
            if (Version.sdkAboveOrEqual(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
                Module_Phone_Api34Compatibility.startServiceForeground(
                    service,
                    notifId,
                    notif!!,
                    mask
                )
            } else
                if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
                    Module_Phone_Api31Compatibility.startForegroundService(service, notifId, notif)
                } else {
                    Module_Phone_Api21Compatibility.startForegroundService(service, notifId, notif)
                }
        }

        /* Call */

        fun canDrawOverlay(context: Context): Boolean {
            if (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) {
                return Module_Phone_Api23Compatibility.canDrawOverlay(context)
            }
            return false
        }

        fun enterPipMode(activity: Activity) {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                Api26Compatibility.enterPipMode(activity)
            }
        }

        fun eventVibration(vibrator: Vibrator) {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                Api26Compatibility.eventVibration(vibrator)
            } else {
                Module_Phone_Api21Compatibility.eventVibration(vibrator)
            }
        }

        fun changeAudioRouteForTelecomManager(connection: Module_Phone_NativeCallWrapper, route: Int): Boolean {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                return Api26Compatibility.changeAudioRouteForTelecomManager(connection, route)
            }
            return false
        }

        /* Contacts */

        fun createShortcutsToContacts(context: Context) {
            if (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) {
                Module_Phone_Api25Compatibility.createShortcutsToContacts(context)
            }
        }

        fun removeShortcuts(context: Context) {
            if (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) {
                Module_Phone_Api25Compatibility.removeShortcuts(context)
            }
        }

        /* Chat */

        fun createShortcutsToChatRooms(context: Context) {
            if (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) {
                Module_Phone_Api25Compatibility.createShortcutsToChatRooms(context)
            }
        }

        fun removeChatRoomShortcut(context: Context, chatRoom: ChatRoom) {
            if (Version.sdkAboveOrEqual(Version.API30_ANDROID_11)) {
                Module_Phone_Api30Compatibility.removeChatRoomShortcut(context, chatRoom)
            }
        }

        fun extractLocusIdFromIntent(intent: Intent): String? {
            if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
                return Module_Phone_Api29Compatibility.extractLocusIdFromIntent(intent)
            }
            return null
        }

        fun setLocusIdInContentCaptureSession(root: View, chatRoom: ChatRoom) {
            if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
                return Module_Phone_Api29Compatibility.setLocusIdInContentCaptureSession(root, chatRoom)
            }
        }

        fun canChatMessageChannelBubble(context: Context): Boolean {
            if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
                return Module_Phone_Api29Compatibility.canChatMessageChannelBubble(context)
            }
            return false
        }

//        suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
//            if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
//                return Api29Compatibility.addImageToMediaStore(context, content)
//            }
//            return Api21Compatibility.addImageToMediaStore(context, content)
//        }

//        suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
//            if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
//                return Api29Compatibility.addVideoToMediaStore(context, content)
//            }
//            return Api21Compatibility.addVideoToMediaStore(context, content)
//        }
//
//        suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
//            if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
//                return Api29Compatibility.addAudioToMediaStore(context, content)
//            }
//            return Api21Compatibility.addAudioToMediaStore(context, content)
//        }

        fun getUpdateCurrentPendingIntentFlag(): Int {
            if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
                return Module_Phone_Api31Compatibility.getUpdateCurrentPendingIntentFlag()
            }
            return Module_Phone_Api21Compatibility.getUpdateCurrentPendingIntentFlag()
        }

        fun getImeFlagsForSecureChatRoom(): Int {
            if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
                return Api26Compatibility.getImeFlagsForSecureChatRoom()
            }
            return Module_Phone_Api21Compatibility.getImeFlagsForSecureChatRoom()
        }

        @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
        fun hasFullScreenIntentPermission(context: Context): Boolean {
            if (Version.sdkAboveOrEqual(34)) {
                return Module_Phone_Api34Compatibility.hasFullScreenIntentPermission(context)
            }
            return true
        }

        @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
        fun requestFullScreenIntentPermission(context: Context): Boolean {
            if (Version.sdkAboveOrEqual(34)) {
                Module_Phone_Api34Compatibility.requestFullScreenIntentPermission(context)
                return true
            }
            return false
        }

        /**
         * 针对三星手机A5070手机，音量键调用时，会同时调用音量键和拨号键
         * @param audioManager AudioManager
         * @return Boolean
         */
        fun volumeDown(context: Context, audioManager: AudioManager): Boolean {
            if (isSamsungA5070()) {
                checkDNDMode(context)
                val currentMusicVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
                val currentCallVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL)
                val maxMusic = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
                val maxCall = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)

                val newCallVol = if (currentCallVolume - 1 > 0) {
                    currentCallVolume - 1
                } else {
                    0
                }
                val ratio = (maxMusic.toFloat() / maxCall.toFloat())
                NLog.e("|jake| => maxMusic : $maxMusic")
                NLog.e("|jake| => maxCall : $maxCall")
                NLog.e("|jake| => ratio : $ratio")
                val newMusicVol = (newCallVol * ratio).toInt()

                NLog.e("|jake| ==============>  down  new music is $newMusicVol  call is $newCallVol")
                audioManager.setStreamVolume(
                    AudioManager.STREAM_VOICE_CALL,
                    newCallVol,
                    AudioManager.FLAG_SHOW_UI
                )
                audioManager.setStreamVolume(
                    AudioManager.STREAM_MUSIC,
                    newMusicVol,
                    AudioManager.FLAG_VIBRATE
                )
                return true
            } else if (isHonor50() || isVivo()) {
                checkDNDMode(context)
                val currentRingVol = audioManager.getStreamVolume(AudioManager.STREAM_RING)
                val currentCallVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL)
                val currentSystemVol = audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM)
                NLog.e("|jake| ==============>  当前音量  ring is $currentRingVol  call is $currentCallVolume SYSTEM IS $currentSystemVol")

                val maxRing = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING)
                val maxCall = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)

                val newCallVol = if (currentCallVolume - 1 > 0) {
                    currentCallVolume - 1
                } else {
                    0
                }

                val ratio = (maxRing.toFloat() / maxCall.toFloat())
                NLog.e("|jake| => maxMusic : $maxRing")
                NLog.e("|jake| => maxCall : $maxCall")
                NLog.e("|jake| => ratio : $ratio")
                val newRingVol = (newCallVol * ratio).toInt()

                NLog.e("|jake| ==============>  down  ring is $newRingVol  call is $newCallVol")
                audioManager.setStreamVolume(
                    AudioManager.STREAM_VOICE_CALL,
                    newCallVol,
                    AudioManager.FLAG_SHOW_UI
                )
                audioManager.setStreamVolume(
                    AudioManager.STREAM_RING,
                    newRingVol,
                    AudioManager.FLAG_VIBRATE
                )
                return true
            }
            return false
        }

        fun volumeUp(context: Context, audioManager: AudioManager): Boolean {
            if (isSamsungA5070()) {
                checkDNDMode(context)
                val currentCallVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL)
                val currentMusicVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
                val maxMusic = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
                val maxCall = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)

                val newCallVol = if (currentCallVolume + 1 < maxCall) {
                    currentCallVolume + 1
                } else {
                    maxCall
                }

                val ratio = (maxMusic.toFloat() / maxCall.toFloat())
                NLog.e("|jake| => maxMusic : $maxMusic")
                NLog.e("|jake| => maxCall : $maxCall")
                NLog.e("|jake| => ratio : $ratio")
                val tmp = (newCallVol * ratio).toInt()
                val newValue = if (tmp < maxMusic) {
                    tmp
                } else {
                    maxMusic
                }

                NLog.e("|jake| ==============>  up  music is $newValue  call is $newCallVol")
                audioManager.setStreamVolume(
                    AudioManager.STREAM_VOICE_CALL,
                    newCallVol,
                    AudioManager.FLAG_SHOW_UI
                )
                audioManager.setStreamVolume(
                    AudioManager.STREAM_MUSIC,
                    newValue,
                    AudioManager.FLAG_VIBRATE
                )
                return true
            } else if (isHonor50() || isVivo()) {
                checkDNDMode(context)
                val currentCallVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL)
                val currentRingVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING)
                val currentSystemVol = audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM)
                NLog.e("|jake| ==============>  当前音量  ring is $currentRingVolume  call is $currentCallVolume SYSTEM IS $currentSystemVol")

                val maxRing = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING)
                val maxCall = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)

                val newCallVol = if (currentCallVolume + 1 < maxCall) {
                    currentCallVolume + 1
                } else {
                    maxCall
                }

                val ratio = (maxRing.toFloat() / maxCall.toFloat())
                NLog.e("|jake| => maxMusic : $maxRing")
                NLog.e("|jake| => maxCall : $maxCall")
                NLog.e("|jake| => ratio : $ratio")
                val tmp = (newCallVol * ratio).toInt()
                val newValue = if (tmp < maxRing) {
                    tmp
                } else {
                    maxRing
                }

                NLog.e("|jake| ==============>  up  ring is $newValue  call is $newCallVol")
                audioManager.setStreamVolume(
                    AudioManager.STREAM_VOICE_CALL,
                    newCallVol,
                    AudioManager.FLAG_SHOW_UI
                )
                audioManager.setStreamVolume(
                    AudioManager.STREAM_RING,
                    newValue,
                    AudioManager.FLAG_VIBRATE
                )
                return true
            }
            return false
        }

        private fun checkDNDMode(context: Context) {
            val notificationManager =
                context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            if (!notificationManager.isNotificationPolicyAccessGranted) {
                context.startActivity(Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS))
            }
        }

        fun isSamsungA5070(): Boolean {
            val manufacturer = Build.MANUFACTURER.lowercase(Locale.getDefault())
            val model = Build.MODEL.lowercase(Locale.getDefault())
            NLog.e("|jake| ==============> Big:: $manufacturer :: $model")
            return manufacturer.contains("samsung") && model.contains("sm-a5070")
        }

        private fun isHonor50(): Boolean {
            val manufacturer = Build.MANUFACTURER.lowercase(Locale.getDefault())
            val model = Build.MODEL.lowercase(Locale.getDefault())
            return manufacturer.contains("honor") && model.contains("nth-an00")
        }

        private fun isVivo(): Boolean {
            val manufacturer = Build.MANUFACTURER.lowercase(Locale.getDefault())
            val model = Build.MODEL.lowercase(Locale.getDefault())
            return manufacturer.contains("vivo") && model.contains("v2072a")
        }


    }
}
